#include "virtualfssession.h"


VirtualFsSession::VirtualFsSession()
{

}



void VirtualFsSession::setSessionFile(const QString & f)
{
    _file = f;
}


/** Structure of session file

Dir
 ----------------------------------------------------------------------------------------------- end --
| 0xAF[1] | name_len[4] | name[name_len] | realName_len[4] | realName[realName_len] | virtual_way_len[4] | virtual_way[virtual_way_len] | 0xFF[1] |
 ------------------------------------------------------------------------------------------------------

File
 ---------------------------------------------------------------------------------------------------------------------------------------
| 0xEF[1] | name_len[4] | name[name_len] | real_way_len[4] | real_way[real_way_len] | virtual_way_len[4] | virtual_way[virtual_way_len] |
 ---------------------------------------------------------------------------------------------------------------------------------------

*/


/*
struct SessionFileData
{
    char type;
    uint name_len;
    char *name;

    uint realName_len;
    char *realName;

    uint virtual_way_len;
    char *virtual_way;
};
*/


/************************************************************/
/** ===================== write session ==================== */
/************************************************************/

inline int VirtualFsSession::endFolder(QFile &file)
{
    uchar ident = 0xFF;
    return file.write((char*)&ident, 1);
}


int VirtualFsSession::writeInfo(QFile & file, VirtualFsObject *fs_obj)
{
    if(fs_obj->isDir())
    {
        qWarning() << __FUNCTION__ << "dir";
        uchar dir_ident = 0xAF;
        uint name_len = fs_obj->name().toUtf8().length();
        file.write((char*)&dir_ident, 1);
        file.write((char*)&name_len, 4);
        file.write(fs_obj->name().toUtf8());

        name_len = fs_obj->virtualWay().toUtf8().length();
        file.write((char*)&name_len, 4);
        file.write(fs_obj->virtualWay().toUtf8());

        bool hidden = fs_obj->isHidden();
        file.write((char *)&hidden, 1);

        return 1;
    }
    else
    {
        qWarning() << __FUNCTION__ << "file";

        uchar file_ident = 0xEF;
        uint name_len = fs_obj->name().toUtf8().length();

        file.write((char*)&file_ident, 1);
        file.write((char*)&name_len, 4);
        file.write(fs_obj->name().toUtf8());

        name_len = fs_obj->realName().toUtf8().length();
        file.write((char*)&name_len, 4);
        file.write(fs_obj->realName().toUtf8());

        name_len = fs_obj->realWay().toUtf8().length();
        file.write((char*)&name_len, 4);
        file.write(fs_obj->realWay().toUtf8());

        name_len = fs_obj->virtualWay().toUtf8().length();
        file.write((char*)&name_len, 4);
        file.write(fs_obj->virtualWay().toUtf8());

        bool hidden = fs_obj->isHidden();
        file.write((char *)&hidden, 1);

        return 0;
    }
}


int VirtualFsSession::recursiveFindAndWrite(QFile & file, VirtualFsObject *fs)
{
    if(!fs->isDir()) return -1;

    /* folder begin */
    writeInfo(file, fs);

    for(int i=0; i < fs->size(); ++i)
    {
        VirtualFsObject *fs_obj = fs->at(i);
        if(fs_obj->isDir())
        {
            recursiveFindAndWrite(file, fs_obj);
        } else {
            writeInfo(file, fs_obj);
        }
    }

    /* end of folder */
    endFolder(file);
    return 0;
}


int VirtualFsSession::saveSession(VirtualFs *fs)
{
    /* не "вроот", а "виртуальный рут", епть */
    VirtualFsObject *vroot = fs->root();
    if(!vroot->size()) {
        QFile::remove(_file);
        return -2;
    }

    QFile file(_file);
    file.open(QFile::WriteOnly);
    if(!file.isOpen()) {
        return -1;
    }

    recursiveFindAndWrite(file, vroot);
    file.close();
    return 0;
}



/************************************************************/
/** ===================== read session ==================== */
/************************************************************/

int VirtualFsSession::recursiveFindAndRead(QFile & file, VirtualFs *fs, VirtualFsObject *fs_o)
{
    QByteArray buf;
    QString name, realName;
    while( !file.atEnd() )
    {
        uchar ident;
        uint nl;
        file.read((char *)&ident, 1);

        if(ident == 0xAF) // folder
        {
            qWarning() << " ======= Folder ======= ";

            file.read((char *)&nl, 4);
            name = QObject::trUtf8(file.read(nl));
            qWarning() << "Name: " << name;

            file.read((char* )&nl, 4);
            buf = file.read(nl);
            qWarning() << "Virtual: " << QObject::trUtf8(buf) << "\n";

            bool hidden;
            file.read((char *)&hidden, 1);

            if(name == "" && buf == "/")
            {
                recursiveFindAndRead(file, fs, fs_o);
            }else
            {
                VirtualFsObject *last = fs->createFolder(fs_o, name);
                last->setVisible(hidden? 0 : 1);
                recursiveFindAndRead(file, fs, last);
            }

        } else if(ident == 0xEF) // file
        {
            qWarning() << " ======= File ======= ";
            file.read((char *)&nl, 4);
            name = QObject::trUtf8(file.read(nl));
            qWarning() << "Name: " << name << "(" << nl << ")";

            file.read((char *)&nl, 4);
            realName = QObject::trUtf8(file.read(nl));
            qWarning() << "Real name: " << realName << "(" << nl << ")";

            file.read((char* )&nl, 4);
            buf = file.read(nl);
            qWarning() << "Real: " << QObject::trUtf8(buf) << "(" << nl << ")";

            VirtualFsObject *last = fs->createFile(fs_o, QObject::trUtf8(buf), name, realName);

            file.read((char* )&nl, 4);
            buf = file.read(nl);
            qWarning() << "Virtual: " << QObject::trUtf8(buf) << "(" << nl << ")\n";

            bool hidden;
            file.read((char *)&hidden, 1);
            last->setVisible(hidden? 0 : 1);

        } else if(ident == 0xFF){
            qWarning() << "==== end folder ===";
            break;
        } else {
            qWarning() << "ATTENTION: session file is wrong!";
            return -2;
        }
    }
    return 0;
}


int VirtualFsSession::restoreSession(VirtualFs *fs)
{
    VirtualFsObject *vroot = fs->root();
    QFile file(_file);
    file.open(QFile::ReadOnly);
    if(!file.isOpen() || file.size() < 1) {
        return -1;
    }

    int ret = recursiveFindAndRead(file, fs, vroot);
    file.close();
    return ret;
}


void VirtualFsSession::dump_help(QFile &file)
{
    QByteArray buf;
    while( !file.atEnd() )
    {
        uchar ident;
        uint nl;
        file.read((char *)&ident, 1);

        if(ident == 0xAF) // folder
        {
            qWarning() << " ======= Folder ======= ";

            file.read((char *)&nl, 4);
            buf = file.read(nl);
            qWarning() << "Name: " << QObject::trUtf8(buf);

            file.read((char* )&nl, 4);
            buf = file.read(nl);
            qWarning() << "Virtual: " << QObject::trUtf8(buf) << "\n";

        } else if(ident == 0xEF) // file
        {
            qWarning() << " ======= File ======= ";
            file.read((char *)&nl, 4);
            buf = file.read(nl);
            qWarning() << "Name: " << QObject::trUtf8(buf) << "(" << nl << ")";

            file.read((char *)&nl, 4);
            buf = file.read(nl);
            qWarning() << "Real name: " << QObject::trUtf8(buf) << "(" << nl << ")";

            file.read((char* )&nl, 4);
            buf = file.read(nl);
            qWarning() << "Real: " << QObject::trUtf8(buf) << "(" << nl << ")";

            file.read((char* )&nl, 4);
            buf = file.read(nl);
            qWarning() << "Virtual: " << QObject::trUtf8(buf) << "(" << nl << ")\n";

        } else if(ident == 0xFF){
            qWarning() << "==== end folder ===";

        } else {
            qWarning() << "ATTENTION: session file is wrong!";
            return;
        }
    }
}


void VirtualFsSession::dump(const QString & fname)
{
    QFile file(fname);
    file.open(QFile::ReadOnly);
    if(!file.isOpen()) {
        qWarning() << __FUNCTION__ << "Error while open out file";
        return;
    }

    dump_help(file);
}
